﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

namespace CashFlow.Entities
{
	public class DateRange
	{
		public DateTime MinDate { get; set; }
		public DateTime MaxDate { get; set; }

		public DateRange(DateTime minDate, DateTime maxDate)
		{
			Contract.Requires<ArgumentOutOfRangeException>(maxDate >= minDate, "maxDate should be greater than or equal to minDate");

			this.MinDate = minDate;
			this.MaxDate = maxDate;
		}

		public DateRange(DateTime minDate)
			: this(minDate, DateTime.MaxValue)
		{
		}

		/// <summary>
		/// Find intersection of the two date ranges
		/// </summary>
		/// <param name="second"></param>
		/// <returns>
		///	A date range that belongs to both date ranges or null if the ranegs have no
		///	common dates.
		/// </returns>
		public DateRange Intersect(DateRange second)
		{
			if (this.MinDate > second.MaxDate || this.MaxDate < second.MinDate)
				return null;

			var minDate = this.MinDate <= second.MinDate ? second.MinDate : this.MinDate;
			var maxDate = this.MaxDate >= second.MaxDate ? second.MaxDate : this.MaxDate;

			return new DateRange(minDate, maxDate); ;
		}

		public IEnumerable<DateTime> GetDates()
		{
			var range = this.MaxDate.Subtract(this.MinDate).Days + 1;
			return Enumerable.Range(0, range).Select(d => this.MinDate.AddDays(d));
		}

		public int Duration
		{
			get
			{
				return this.MaxDate.Subtract(this.MinDate).Days + 1;
			}
		}

		public static DateRange GetMonthRange(DateTime date)
		{
			var minDate = new DateTime(date.Year, date.Month, 1);
			var maxDate = new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1);

			return new DateRange(minDate, maxDate);
		}

		public static DateRange GetRangeForDays(DateTime date, int days)
		{
			return new DateRange(date, date.AddDays(days));
		}
	}
}
